package controller

import (
	"fmt"
	vd "github.com/bytedance/go-tagexpr/v2/validator"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"go-gin-api/app/model/response"
	"go-gin-api/app/service"
	"go-gin-api/core/database"
	"go-gin-api/core/log"
	"go-gin-api/core/middleware"
	"go-gin-api/exception"
	"gorm.io/gorm"
)

type Base struct {
	Orm    *gorm.DB
	Ctx    *gin.Context
	Errors error
}

func (b *Base) AddError(err error) {
	if b.Errors == nil {
		b.Errors = err
	} else if err != nil {
		//b.Logger.Error(err)
		b.Errors = fmt.Errorf("%v; %w", b.Errors, err)
	}
}

func (b *Base) MakeOrm(c *gin.Context) *Base {
	b.Orm = database.GetContextDB(c)
	return b
}

func (b *Base) MakeService(c *service.Service) *Base {
	c.Orm = b.Orm
	return b
}

// MakeContext 设置http上下文
func (b *Base) MakeContext(c *gin.Context, classValue ...string) *Base {
	if len(classValue) > 0 {
		c.Set(log.CLASS, classValue[0])
	}
	c.Set(log.DOMAIN, exception.Domain)
	c.Set(log.KINGDOM, exception.RunMode)
	b.Ctx = c
	return b
}

// Bind 参数校验
func (b *Base) Bind(d interface{}, bindings ...binding.Binding) *Base {
	var err error
	if len(bindings) == 0 {
		bindings = middleware.Constructor.GetBindingForGin(d)
	}
	for i := range bindings {
		if bindings[i] == nil {
			err = b.Ctx.ShouldBindUri(d)
		} else {
			err = b.Ctx.ShouldBindWith(d, bindings[i])
		}
		if err != nil && err.Error() == "EOF" {
			//b.Logger.Warn("request body is not present anymore. ")
			err = nil
			continue
		}
		if err != nil {
			b.AddError(err)
			break
		}
	}
	//vd.SetErrorFactory(func(failPath, msg string) error {
	//	return fmt.Errorf(`"validation failed: %s %s"`, failPath, msg)
	//})
	if err1 := vd.Validate(d); err1 != nil {
		b.AddError(err1)
	}
	return b
}

func (b Base) OK() {
	response.OK(b.Ctx)
}

func (b Base) OKData(data interface{}) {
	response.OKWithData(data, b.Ctx)
}
func (b Base) OKWithPage(data interface{}, count, pageIndex, pageSize int) {
	rep := make(map[string]interface{}, 0)
	rep["list"] = data
	rep["count"] = count
	rep["pageIndex"] = pageIndex
	rep["pageSize"] = pageSize
	response.OKWithData(data, b.Ctx)
}

// Error 通常错误数据处理
func (b Base) Error() {
	response.Fail(b.Ctx)
}

func (b Base) ErrorMessage(err error, msg ...string) {
	apiError, ok := err.(*exception.Error)
	if !ok {
		// 以下七行代码为了防止传入nil出错以及传入系统内部err时，可以自定义msg
		message := "服务器开小差了，过会儿重试"
		if err != nil && len(msg) <= 0 { // 错误信息存在，且未自定义提示信息
			message = err.Error()
		}
		if len(msg) > 0 { // 自定义提示信息
			message = msg[0]
		}
		response.FailWithMessage(exception.SystemErrorCode, message, b.Ctx)
		return
	}
	response.FailWithMessage(apiError.Code, apiError.Message, b.Ctx)
}
